module dgl.graphics.TexSeqPlayer;

import dgl.Event;
import dgl.Rectangle;
import dgl.Vector2;
import dgl.graphics.Texture2D;
import dgl.graphics.SpriteBatch;
import dgl.GameTime;

enum ArrangeMode
{
	Horizontal,
	Vertical
}

class TexSeqPlayer
{
	private SpriteBatch m_spriteBatch;

	private Texture2D[] m_textureList;

	public Texture2D[] textureList()
	{
		return m_textureList;
	}

	public void textureList( Texture2D[] textureList )
	{
		if( m_textureList.length <= textureList.length )
		{
			m_textureList.length = textureList.length +1;
		}
		m_textureList = textureList;
	}

	private Rectangle m_rectInTexture;

	public Rectangle rectInTexture()
	{
		return m_rectInTexture;
	}

	public void rectInTexture( Rectangle rectInTexture )
	{
		m_rectInTexture = rectInTexture;
	}

	private Rectangle m_rectToDraw;

	public Rectangle rectToDraw()
	{
		return m_rectToDraw;
	}

	public void rectToDraw( Rectangle rectToDraw )
	{
		m_rectToDraw = rectToDraw;
	}

	private float m_totalTime;

	public float totalTime()
	{
		return m_totalTime;
	}
	
	public void totalTime( float totalTime )
	{
		m_totalTime = totalTime;
	}
	
	private ArrangeMode m_arrangeMode;
	
	public ArrangeMode arrangeMode()
	{
		return m_arrangeMode;
	}
	
	public void arrangeMode( ArrangeMode arrangeMode )
	{
		m_arrangeMode = arrangeMode;
	}
	
	private bool m_isLoop;
	
	public bool isLoop()
	{
		return m_isLoop;
	}
	
	public void isLoop( bool isLoop )
	{
		m_isLoop = isLoop;
	}
	
	public Vector2 position()
	{
		return Vector2( m_rectToDraw.x, m_rectToDraw.y );
	}
	
	public void position( Vector2 position )
	{
		m_rectToDraw.x = cast(int)position.x;
		m_rectToDraw.y = cast(int)position.y;
	}
	
	public Vector2 sizeToDraw()
	{
		return Vector2( m_rectToDraw.width, m_rectToDraw.y );
	}
	
	public void sizeToDraw( Vector2 sizeToDraw )
	{
		m_rectToDraw.width = cast(int)sizeToDraw.x;
		m_rectToDraw.height = cast(int)sizeToDraw.y;
	}
	
	private float m_elapseTime;
	private float m_delayTime;

	private Texture2D m_curTexture;

	private int m_textureID;

	private bool m_isPlaying;

	private int m_totalPicNum;
	
	public Event!(TexSeqPlayer, EventArgs) finish;
	
	public this( SpriteBatch spriteBatch )
	{
		this( spriteBatch, null, Vector2.zero, Vector2.zero, 0, ArrangeMode.Horizontal, false );
	}
	
	public this( SpriteBatch spriteBatch,
	             Texture2D texture,
	             Vector2 sizePerPic,
	             Vector2 position,
	             float totalTime,
	             ArrangeMode picArrangeMode,
	             bool isLoop )
	{
		m_spriteBatch = spriteBatch;
		m_textureList = new Texture2D[0];
		if( texture )
		{
			m_textureList.length = m_textureList.length + 1;
			m_textureList[m_textureList.length-1] = texture;
		}
		m_rectInTexture = Rectangle( 0, 0, cast(int)sizePerPic.x, cast(int)sizePerPic.y );
		m_rectToDraw = Rectangle( cast(int)position.x, cast(int)position.y, cast(int)sizePerPic.x, cast(int)sizePerPic.y );
		m_totalTime = totalTime;
		m_delayTime = totalTime;
		m_elapseTime = 0;
		m_totalPicNum = 0;
		if( m_textureList.length == 1 )
		{
			m_curTexture = m_textureList[0];
			m_totalPicNum += this.numOfRectInTexture( m_curTexture );
			m_delayTime = m_totalTime / m_totalPicNum;
		}
		else
		{
			m_curTexture = null;
		}
		m_textureID = 0;
		m_isPlaying = false;
		m_arrangeMode = picArrangeMode;
		m_isLoop = isLoop;
	}
	
	public void addTexture( Texture2D texture )
	{
		m_textureList.length = m_textureList.length + 1;
		m_textureList[m_textureList.length-1] = texture;
		if( m_curTexture is null )
		{
			m_curTexture = m_textureList[0];
		}
		m_totalPicNum += this.numOfRectInTexture( texture );
		m_delayTime = m_totalTime / m_totalPicNum;
	}
	
	public void removeTexture( Texture2D texture )
	{
		for( int i = 0; i < m_textureList.length; i++ )
		{
			if( m_textureList[i] == texture )
			{
				for( int j = i; j < m_textureList.length -1; j++ )
				{
					m_textureList[j] = m_textureList[j+1];
				}
				m_textureList.length = m_textureList.length - 1;
			}
			m_totalPicNum -= this.numOfRectInTexture( texture );
			m_delayTime = m_totalTime / m_totalPicNum;
		}
	}
	
	public void play()
	{
		m_isPlaying = true;
	}
	
	public void pause()
	{
		m_isPlaying = false;
	}
	
	public void stop()
	{
		m_isPlaying = false;
		m_curTexture = m_textureList[0];
		m_rectInTexture.x = 0;
		m_rectInTexture.y = 0;
	}
	
	private int numOfRectInTexture( Texture2D texture )
	{
		return texture.width / m_rectInTexture.width * texture.height / m_rectInTexture.height;
	}
	
	package void onFinish( TexSeqPlayer sender, EventArgs e )
	{
		this.finish( sender, e );
	}
	
	private bool hasNextRect( Texture2D texture )
	{
		switch( m_arrangeMode )
		{
		case ArrangeMode.Horizontal:
			if( m_rectInTexture.x + m_rectInTexture.width >= texture.width )
			{
				if( m_rectInTexture.y + m_rectInTexture.height >= texture.height )
				{
					return false;
				}
				m_rectInTexture.x = 0;
				m_rectInTexture.y += m_rectInTexture.height;
				return true;
			}
			m_rectInTexture.x += m_rectInTexture.width;
			return true;
		case ArrangeMode.Vertical:
			if( m_rectInTexture.y + m_rectInTexture.height >= texture.height )
			{
				if( m_rectInTexture.x + m_rectInTexture.width >= texture.width )
				{
					return false;
				}
				m_rectInTexture.y = 0;
				m_rectInTexture.x += m_rectInTexture.width;
				return true;
			}
			m_rectInTexture.y += m_rectInTexture.height;
			return true;
		default:
			return false;
		}
		return false;
	}
	
	public void update( GameTime gameTime )
	{
		if( !m_isPlaying )
		{
			return;
		}
		m_elapseTime += gameTime.elapsedGameTime;
		if( m_elapseTime >= m_delayTime )
		{
			if( !this.hasNextRect(m_curTexture) )
			{
				m_textureID += 1;
				if( m_textureID < m_textureList.length )
				{
					m_curTexture = m_textureList[m_textureID];
					m_rectInTexture.x = 0;
					m_rectInTexture.y = 0;
				}
				else
				{
					this.onFinish(this, EventArgs.empty);
					if( m_isLoop )
					{
						m_curTexture = m_textureList[0];
						m_rectInTexture.x = 0;
						m_rectInTexture.y = 0;
					}
					else
					{
						m_isPlaying = false;
					}
					m_textureID = 0;
				}
			}
			m_elapseTime = 0;
		}
	}
	
	public void draw( GameTime gameTime )
	{
		m_spriteBatch.begin();
		
		if( m_curTexture )
		{
			m_spriteBatch.draw( m_curTexture, m_rectToDraw, m_rectInTexture );
		}
		
		m_spriteBatch.end();
	}
}